/*
 * Class for performing lookups on the database.
 * Give sentence using setSentence()
 * Make lookup using eval()
 * See result using getResult() or toString()
 *
 * @ author Paul Wagner, René Pickhardt
 */
package complet.db.genetics;

import complet.db.DBConn;
import complet.db.Word;
import complet.helper.ConfigHelper;
import complet.helper.IOHelper;
import java.util.TreeMap;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;

public class Retrieval extends DBConn {

    // PROPERTIES
    private String[] words;
    private String offset;
    //private TreeMap<String, Word> res;
    private TreeMap<String, Word> res1 = new TreeMap<String, Word>();
    private TreeMap<String, Word> res2 = new TreeMap<String, Word>();
    private TreeMap<String, Word> res3 = new TreeMap<String, Word>();
    private TreeMap<String, Word> res4 = new TreeMap<String, Word>();
    private String NAME_KEY = ConfigHelper.NAME_KEY;
    private String COUNT_KEY = ConfigHelper.COUNT_KEY;
    private String RELLOC_KEY = ConfigHelper.RELLOC_KEY;
    private boolean FULL_LIST = false;


    /*
     * Constructor using ConfigHelper
     */
    public Retrieval() {
        this(ConfigHelper.DB_PATH, ConfigHelper.MAX_RELATIONS, ConfigHelper.NAME_KEY, ConfigHelper.COUNT_KEY, ConfigHelper.CACHE_TYPE, ConfigHelper.BUFFER);
    }

    /*
     * Constructor using manual config values
     *
     */
    public Retrieval(String database, int max_relations, String name_key, String count_key, String cache_type, Boolean buffer) {
        super(database, max_relations, name_key, cache_type, buffer);
        this.NAME_KEY = name_key;
        this.COUNT_KEY = count_key;

    }

    // GETTER AND SETTER
    public String getCOUNT_KEY() {
        return COUNT_KEY;
    }

    public String getNAME_KEY() {
        return NAME_KEY;
    }

    public TreeMap<String, Word> getRes1() {
        return res1;
    }

    public TreeMap<String, Word> getRes2() {
        return res2;
    }

    public TreeMap<String, Word> getRes3() {
        return res3;
    }

    public TreeMap<String, Word> getRes4() {
        return res4;
    }

    // METHODS

    /*
     * Set sentence before performing lookup
     * Please be aware of the fact, that your sentence shouldn't be longer than your DB provides!
     *
     * @param words Words in the sentence
     * @param offest Letters known from the current word
     */
    public void setSentence(String[] words, String offset) {
        this.words = words;
        if (this.words.length > 4) {
            this.words = null;
            IOHelper.log("(Retrieval) WARNING: setSentence() Wordlength out of bounds!");
        }
        this.offset = offset;
    }

    /*
     * Perfoms lookup
     *
     * @return lookuptime Evaluating time in ms
     */
    public double eval() {
        //IOHelper.log("(Retrieval) Evaluate lookup");
        res1 = new TreeMap<String, Word>();
        res2 = new TreeMap<String, Word>();
        res3 = new TreeMap<String, Word>();
        res4 = new TreeMap<String, Word>();

        long start_time = System.nanoTime();
        try {
            int len = this.words.length;
            Node[] startNode = new Node[len];
            TreeMap<String, Word> res = null;

            for (int i = 0; i < len; i++) {
                switch (i) {
                    case 0:
                        res = res4;
                        break;
                    case 1:
                        res = res3;
                        break;
                    case 2:
                        res = res2;
                        break;
                    case 3:
                        res = res1;
                        break;
                }

                startNode[i] = getWordIndex().get(this.NAME_KEY, this.words[i]).getSingle();
                if (startNode[i] == null) {
                    continue;
                }

                for (Relationship rel : startNode[i].getRelationships(getDn()[len - i], Direction.OUTGOING)) {
                    int cnt = 0;
                    int c_cnt = 0;
                    double relglob = 0;
                    double c_relglob = 0;
                    double relloc = 0;
                    double c_relloc = 0;

                    String tmp = (String) rel.getEndNode().getProperty(this.NAME_KEY);
                    if (this.FULL_LIST || tmp.startsWith(this.offset)) {
                        if (res.containsKey(tmp)) {
                            cnt = res.get(tmp).getSUM_COUNT();
                            relloc = res.get(tmp).getAVG_REL();
                        }
                        c_cnt = 0;
                        c_relloc = 0;
                        c_cnt = (Integer) rel.getProperty(COUNT_KEY);
                        if (rel.hasProperty(RELLOC_KEY)) {
                            c_relloc = (Double) rel.getProperty(RELLOC_KEY);
                        }

                        Word new_word = new Word(rel.getEndNode(), tmp, cnt + c_cnt, relloc + c_relloc, 0);
                        res.put(tmp, new_word);
                    }
                }
            }
        } catch (Exception e) {
            IOHelper.logError("(Retrieval.eval()) " + e.getMessage());
            return -1;
        }

        long end_time = System.nanoTime();
        return (double) (Math.round((double) (end_time - start_time) / 1000)) / 1000;
    }
}
